﻿using Core.Interface;
using NModbus;
using System;
using System.Net;
using System.Net.Sockets;

namespace ModBus.Mode
{
    public class ModBusTCP : ModBusDevice
    {
        TcpClient client;
        IModbusMaster master;

        private IPEndPoint iPEndPoint;
        public IPEndPoint IPEndPoint
        {
            get { return iPEndPoint; }
            set { iPEndPoint = value; }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private readonly object rwLock = new object();

        public ModBusTCP(string name)
        {
            Name = name;
        }

        public override bool Connect()
        {
            try
            {
                var factory = new ModbusFactory();
                client = new TcpClient();
                client.Connect(iPEndPoint);
                master = factory.CreateMaster(client);
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }

        public override void Close()
        {
            try
            {
                master?.Dispose();
                client?.Close();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }

        const byte slaveAddress = 0x01;
        public override bool ReadBit(ushort startAddress, ushort size, out bool[] values)
        {
            lock (rwLock)
            {
                try
                {
                    values = master?.ReadCoils(slaveAddress, startAddress, size);
                    return true;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                }
            }
        }

        public override bool ReadRegister(ushort startAddress, ushort size, out ushort[] values)
        {
            lock (rwLock)
            {
                try
                {
                    values = master?.ReadHoldingRegisters(slaveAddress, startAddress, size);
                    return true;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                }
            }
        }

        public override bool WriteBit(ushort startAddress, ushort size, bool[] values)
        {
            lock (rwLock)
            {
                try
                {
                    master?.WriteMultipleCoils(slaveAddress, startAddress, values);
                    return true;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                }
            }
        }

        public override bool WriteRegister(ushort startAddress, ushort size, ushort[] values)
        {
            lock (rwLock)
            {
                try
                {
                    master?.WriteMultipleRegisters(slaveAddress, startAddress, values);
                    return true;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                }
            }
        }
    }
}
